# coding:utf-8
import json
import logging
import os
from configparser import ConfigParser
from pathlib import Path

from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest

root_dir = Path(__file__).parent
# # 创建解析器实例
config = ConfigParser()
# # 读取配置文件
config.read(os.path.join(root_dir, 'config.ini'))

sdksource = config.get("aliyun.default", "sdksource")
logpath = config.get("aliyun.default", "logpath")

# ascm
product_ascm = config.get("aliyun.ascm", "product")
version_ascm = config.get("aliyun.ascm", "version")
endpoint_ascm = config.get("aliyun.ascm", "endpoint")

# ecs
product_ecs = config.get("aliyun.ecs", "product")
version_ecs = config.get("aliyun.ecs", "version")
endpoint_ecs = config.get("aliyun.ecs", "endpoint")

g_version = "2014-05-26"

logging.basicConfig(filename=logpath + "ResourceApiWrapper.log",
                    format="%(asctime)s %(name)s:%(levelname)s:%(message)s",
                    datefmt="%Y-%m-%d %H:%M:%S", level=logging.DEBUG)
logger = logging.getLogger()


class ResourceApiWrapper:
    def __init__(self, apigateway, resourcegroup, organization, region, ak, sk, timeout=3000, verify=None,
                 sdksource="ghca", proxy=None):
        self._apigateway = apigateway
        self._resourcegroup = resourcegroup
        self._organization = organization
        self._region = region
        self._ak = ak
        self._sk = sk
        self._timeout = timeout
        self._sdksource = sdksource
        self.verify = verify
        self.proxy = proxy
        logger.info(
            "ResourceApiWrapper init...,apigateway={},resourcegroup={},organization={},region={}".format(
                apigateway, resourcegroup, organization, region)
        )
        self._client = AcsClient(self._ak, self._sk, self._region, timeout=timeout)

    # 定义一个函数来获取键名不区分大小写的值

    def _callapi_ascm(self, action, v_uripattern=None, v_method="POST", v_regionid=None, v_zoneid=None,
                      v_instanceid=None, **kwargs):
        req = CommonRequest()
        req.set_product(product_ascm)
        req.set_version(version_ascm)
        req.set_action_name(action)
        req.set_endpoint(endpoint_ascm)
        #req.set_endpoint(self._apigateway)
        if v_uripattern:
            req.set_uri_pattern(v_uripattern)
        if v_regionid:
            req.add_header("x-acs-regionid", v_regionid)
        else:
            req.add_header("x-acs-regionid", self._region)
        # zoneid参数
        if v_zoneid:
            req.add_header("x-acs-zoneid", v_zoneid)
            req.add_query_param("ZoneId", v_zoneid)
        if v_instanceid:
            req.add_query_param("InstanceId", v_instanceid)
        if kwargs:
            for k, v in kwargs.items():
                if k == "ResourceGroupId":
                    req.add_header("x-acs-resourcegroupid", v)
                else:
                    req.add_body_params(k, v)
        req.set_method(v_method)
        req.set_content_type('application/json')
        req.add_header("x-acs-caller-sdk-source", self._sdksource)
        r = self._client.do_action_with_exception(req)
        response = json.loads(r.decode())
        formatresponse = format_response(response)
        return formatresponse

    def _callapi_ecs(self, action, v_method="POST", v_regionid=None, v_zoneid=None, v_instanceid=None, **kwargs):
        req = CommonRequest()
        req.set_product(product_ecs)
        req.set_version(version_ecs)
        req.set_action_name(action)
        req.set_endpoint(endpoint_ecs)
        #req.set_endpoint(self._apigateway)
        if v_regionid:
            req.add_header("x-acs-regionid", v_regionid)
        else:
            req.add_header("x-acs-regionid", self._region)

        # zoneid参数
        if v_zoneid:
            req.add_header("x-acs-zoneid", v_zoneid)
            req.add_query_param("ZoneId", v_zoneid)

        if v_instanceid:
            req.add_query_param("InstanceId", v_instanceid)
        if kwargs:
            for k, v in kwargs.items():
                if k == "ResourceGroupId":
                    req.add_header("x-acs-resourcegroupid", v)
                elif k == "OrganizationId":
                    req.add_header("x-acs-organizationid", v)
                else:
                    req.add_query_param(k, v)
        req.set_method(v_method)
        req.add_header("x-acs-caller-sdk-source", self._sdksource)
        logger.info("action name: {},req:{}".format(action, str(req)))
        r = self._client.do_action_with_exception(req)
        response = json.loads(r.decode())
        formatresponse = format_response(response)
        logger.debug("action name: {},response:{}".format(action, formatresponse))
        return formatresponse

    def connect_check(self):
        logger.info("method: connect check")
        return self._callapi_ecs("DescribeRegions")

    def list_regions(self):
        """
        查询region列表
        :return:
        """
        logger.info("method: list_regions")
        return self._callapi_ecs("DescribeRegions")

    def list_zones(self, region_id=None, **kwargs):
        """
        查询可用区列表
        RegionId 必需字段
        :return:
        """
        logger.info("method: list_zones")
        if not region_id:
            kwargs['RegionId'] = regionId
        else:
            kwargs['RegionId'] = region_id
        return self._callapi_ecs("DescribeZones", **kwargs)

    def list_instances(self, region_id, pageno=None, pagesize=None, instance_id=None, organization_id=None, resourcegroup_id=None, **kwargs):
        """
        查询ecs列表或详情
        :param instance_id: ecs实例id,不传则查询ecs列表
        :param kwargs:
        :return:
        """
        logger.info("method: list_instances")
        if not region_id:
            kwargs['RegionId'] = regionId
        else:
            kwargs['RegionId'] = region_id
        if instance_id:
            kwargs['InstanceIds'] = [instance_id]
        if resourcegroup_id:
            kwargs['ResourceGroupId'] = resourcegroup_id
            if organization_id:
                kwargs['OrganizationId'] = organization_id
            else:
                kwargs['OrganizationId'] = organizationId
        if pageno:
            kwargs['PageNumber'] = pageno
        else:
            kwargs['PageNumber'] = 1
        if pagesize:
            size = pagesize
            if pagesize > 100:
                size = 100
            kwargs['PageSize'] = size
        else:
            kwargs['PageSize'] = 100
        return self._callapi_ecs("DescribeInstances", **kwargs)

    def list_disks(self, region_id=None, instance_id=None, pageno=None, pagesize=None, disk_ids=None, snapshot_id=None, **kwargs):
        """
        查询磁盘列表或磁盘详情
        :param disk_ids: 云盘或本地盘ID。一个带有格式的JSON数组，最多支持100个ID，用半角逗号（,）隔开。
        :param instance_id: ecs实例id
        :param kwargs:
        :return:
        """
        logger.info("method: list_disks")
        if not region_id:
            kwargs['RegionId'] = regionId
        else:
            kwargs['RegionId'] = region_id
        if instance_id:
            kwargs['InstanceId'] = instance_id
        if disk_ids:
            kwargs['DiskIds'] = [disk_ids]
        if snapshot_id:
            kwargs['SnapshotId'] = snapshot_id
        if pageno:
            kwargs['PageNumber'] = pageno
        else:
            kwargs['PageNumber'] = 1
        if pagesize:
            size = pagesize
            if pagesize > 100:
                size = 100
            kwargs['PageSize'] = size
        else:
            kwargs['PageSize'] = 100
        return self._callapi_ecs("DescribeDisks", **kwargs)

    def create_snapshot(self, disk_id, **kwargs):
        """
        创建快照
        :param disk_id: 云盘或本地盘ID
        :param kwargs:
        :return:
        """
        logger.info("method: create_snapshot")
        if not disk_id:
            raise ValueError('disk_id is required')
        kwargs['DiskId'] = disk_id
        return self._callapi_ecs("CreateSnapshot", **kwargs)

    def list_snapshot(self, region_id=None, snapshot_ids=None, disk_id=None, pageno=None, pagesize=None, instance_id=None,
                      **kwargs):
        """
        查询快照列表
        :param instance_id: 实例id
        :param disk_id: 磁盘id
        :param snapshot_ids: 快照id快照标识编码。取值可以由多个快照ID组成一个JSON数组，最多支持100个ID，ID之间用半角逗号（,）隔开。
        :param kwargs:
        :return:
        """
        logger.info("method: list_snapshot")
        if not region_id:
            kwargs['RegionId'] = regionId
        else:
            kwargs['RegionId'] = region_id
        if instance_id:
            kwargs['InstanceId'] = instance_id
        if disk_id:
            kwargs['DiskId'] = disk_id
        if snapshot_ids:
            kwargs['SnapshotIds'] = [snapshot_ids]
        if pageno:
            kwargs['PageNumber'] = pageno
        else:
            kwargs['PageNumber'] = 1
        if pagesize:
            size = pagesize
            if pagesize > 100:
                size = 100
            kwargs['PageSize'] = size
        else:
            kwargs['PageSize'] = 100
        return self._callapi_ecs("DescribeSnapshots", **kwargs)

    def delete_snapshot(self, snapshot_id, **kwargs):
        """
        删除快照
        :param snapshot_id: 快照id
        :param kwargs:
        :return:
        """
        logger.info("method: delete_snapshot")
        if not snapshot_id:
            raise ValueError('snapshot_id is required')
        kwargs['SnapshotId'] = snapshot_id
        return self._callapi_ecs("DeleteSnapshot", **kwargs)

    def create_snapshotgroup(self, region_id, instance_id, snapshotgroup_name=None, excludedisk_ids=None, **kwargs):
        logger.info("method: create_snapshotgroup")
        if not region_id:
            kwargs['RegionId'] = regionId
        else:
            kwargs['RegionId'] = region_id
        if not instance_id:
            raise ValueError('instance_id is required')
        kwargs['InstanceId'] = instance_id
        if snapshotgroup_name:
            kwargs['Name'] = snapshotgroup_name
        if excludedisk_ids:
            excludedisk_list = excludedisk_ids.split(',')
            for index, value in enumerate(excludedisk_list, start=1):
                key = f"ExcludeDiskId.{index}"
                kwargs[key] = value
        return self._callapi_ecs("CreateSnapshotGroup", **kwargs)

    def list_snapshotgroup(self, region_id=None, group_ids=None, pageno=None, pagesize=None, instance_id=None,
                           **kwargs):
        logger.info("method: list_snapshotgroup")
        if not region_id:
            kwargs['RegionId'] = regionId
        else:
            kwargs['RegionId'] = region_id
        if group_ids:
            groupid_list = group_ids.split(',')
            for index, value in enumerate(groupid_list, start=1):
                key = f"SnapshotGroupId.{index}"
                kwargs[key] = value
        if pageno:
            kwargs['PageNumber'] = pageno
        else:
            kwargs['PageNumber'] = 1
        if pagesize:
            size = pagesize
            if pagesize > 100:
                size = 100
            kwargs['PageSize'] = size
        else:
            kwargs['PageSize'] = 100
        if instance_id:
            kwargs['InstanceId'] = instance_id
        return self._callapi_ecs("DescribeSnapshotGroups", **kwargs)

    def delete_snapshotgroup(self, region_id, snapshotgroup_id, **kwargs):
        logger.info("method: delete_snapshotgroup")
        if not region_id:
            kwargs['RegionId'] = regionId
        else:
            kwargs['RegionId'] = region_id
        if not snapshotgroup_id:
            raise ValueError('snapshotgroup_id is required')
        kwargs['SnapshotGroupId'] = snapshotgroup_id
        return self._callapi_ecs("DeleteSnapshotGroup", **kwargs)

    def create_disk(self, region_id, snapshot_id, zone_id, disk_name, disk_size, disk_type, description, **kwargs):
        logger.info("method: create_disk")
        if not zone_id:
            raise ValueError('create_disk, zone_id is required')
        kwargs['ZoneId'] = zone_id
        if not region_id:
            kwargs['RegionId'] = regionId
        else:
            kwargs['RegionId'] = region_id
        if snapshot_id:
            kwargs['SnapshotId'] = snapshot_id
        if disk_name:
            kwargs['DiskName'] = disk_name
        if disk_size:
            kwargs['Size'] = disk_size
        if disk_type:
            kwargs['DiskCategory'] = disk_type
        else:
            kwargs['DiskCategory'] = 'cloud_pperf'
        if description:
            kwargs['Description'] = description
        return self._callapi_ecs("CreateDisk", **kwargs)

    def attach_disk(self, instance_id, disk_id, delete_with_instance=False, bootable=False, password=None, **args):
        """
        挂载磁盘
        :param instance_id:  ecs实例id
        :param disk_id: 待挂载的磁盘id
        :param delete_with_instance: 释放实例时，该云盘是否随实例一起释放。true：释放，false：不释放，默认值：false
        :param args:
        :return:
        """
        logger.info("method: attach_disk")
        if not instance_id or not disk_id:
            raise ValueError('AttachDisk instance_id and disk_id are required')
        if bootable:
            args['Bootable'] = True
            if password:
                args['Password'] = password
            # if not password:
            #     raise ValueError('AttachDisk systemdisk, apassword is required')
            # args['Bootable'] = True
            # args['Password'] = password
        args['InstanceId'] = instance_id
        args['DiskId'] = disk_id
        args['DeleteWithInstance'] = delete_with_instance
        return self._callapi_ecs("AttachDisk", **args)

    def detach_disk(self, instance_id, disk_id, delete_with_instance=True, **args):
        """
        卸载磁盘
        :param instance_id:  ecs实例id
        :param disk_id: 待卸载的磁盘id
        :param delete_with_instance:
        卸载系统盘时，设置自动释放属性。表示释放ECS实例时，是否同时释放该系统盘。true：释放。false：不释放。云盘会被保留下来。默认值：true
        :param args:
        :return:
        """
        logger.info("method: detach_disk")
        if not instance_id or not disk_id:
            raise ValueError('DetachDisk instance_id and disk_id are required')
        args['InstanceId'] = instance_id
        args['DiskId'] = disk_id
        args['DeleteWithInstance'] = delete_with_instance
        return self._callapi_ecs("DetachDisk", **args)

    def delete_disk(self, disk_id):
        args = dict();
        args['DiskId'] = disk_id
        logger.info("method: delete_disk")
        return self._callapi_ecs("DeleteDisk", **args)

    def start_instance(self, instance_id, **kwargs):
        """
        上电ecs
        :param instance_id: ecs实例id
        :return:
        """
        logger.info("method: start_instance")
        if not instance_id:
            raise ValueError('StartInstance instance_id is required')
        kwargs['InstanceId'] = instance_id
        return self._callapi_ecs("StartInstance", **kwargs)

    def stop_instance(self, instance_id, **kwargs):
        """
        下电ecs
        :param instance_id: ecs实例id
        :return:
        """
        logger.info("method: stop_instance")
        if not instance_id:
            raise ValueError('StopInstance instance_id is required')
        kwargs['InstanceId'] = instance_id
        return self._callapi_ecs("StopInstance", **kwargs)

    def status_instance(self, instance_id, **kwargs):
        logger.info("method: status_instance")
        kwargs['InstanceId.1'] = instance_id
        kwargs['RegionId'] = regionId
        return self._callapi_ecs("DescribeInstanceStatus", **kwargs)

    def list_organizations(self, **kwargs):
        pattern = "/ascm/auth/organization/queryList"
        logger.info("method: list_organizations")
        return self._callapi_ascm("GetOrganizationList", v_uripattern=pattern, **kwargs)

    def des_organization(self, organization_id, **kwargs):
        pattern = "/ascm/auth/organization/query"
        logger.info("method: des_organization")
        if not organization_id:
            kwargs['id'] = str(organizationId)
        else:
            kwargs['id'] = str(organization_id)
        return self._callapi_ascm("GetOrganization", v_uripattern=pattern, **kwargs)

    def list_resourcegroup_byorg(self, organization_id, **kwargs):
        pattern = "/ascm/auth/organization/resourceGroupList"
        logger.info("method: list_resourcegroup_byorg")
        if not organization_id:
            kwargs['id'] = str(organizationId)
        else:
            kwargs['id'] = str(organization_id)
        return self._callapi_ascm("ListResourceGroupByOrgId", v_uripattern=pattern, **kwargs)

    def modify_diskspec(self, disk_id, disk_category, **kwargs):
        logger.info("method: modify_diskspec")
        if not disk_id:
            raise ValueError('modify_diskspe, disk_id is required')
        kwargs['DiskId'] = disk_id
        if disk_category:
            kwargs['DiskCategory'] = disk_category
        return self._callapi_ecs("ModifyDiskSpec", **kwargs)

    """ RDS """

    def list_dbinstances(self):
        """
        查询RDS实例列表
        :return:
        """
        pass

    def DescribeDBInstances(self):
        pass

    def DescribeDatabases(self, dbinstance_id, **kwargs):
        pass


def get_case_insensitive_value(data, key):
    # 将键名转换为小写（或大写）
    lower_key = key.lower()
    # 遍历字典的键，查找匹配项
    for k in data.keys():
        if k.lower() == lower_key:
            return data[k]
    # 如果没有找到匹配项，则返回 None 或者默认值
    return None


# 定义一个函数来获取非空的值
def get_non_empty_value(data, keys):
    for key in keys:
        if key in data and data[key]:  # 检查 key 是否存在并且值不为空
            return data[key]
    return None  # 如果所有值都为空，则返回 None


def building(status_code, body, error=""):
    response = {
        "StatusCode": status_code,
        "Body": str(body).replace("'", '"').replace("True", "true").replace("False", "false"),
        "Error": error
    }
    return json.dumps(response, ensure_ascii=False)


def format_response(response):
    status_code = get_non_empty_value(response, ["code", "Code", "httpStatus"])
    if not status_code or str(status_code).startswith('2'):
        return building(200, body=response, error="")
    else:
        message = get_non_empty_value(response, ["message", "Message", "errorMessage"])
        return building(500, body="", error=message)